package com.neu;

import com.neu.discovery.Registry;
import com.neu.discovery.RegistryConfig;
import com.neu.exceptions.NetworkException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import com.neu.rpcBootstrap;

/**
 *
 * @author 杜佳辉
 * @version 1.0
 * @date 2024-12-05-20:48
 */
@Getter
@Slf4j
public class ReferenceConfig<T> {
    private Class<T> interfaceProvider;
    private Registry registry;

    public void setRegistry(Registry registry) {
        this.registry = registry;
    }

    public void setServiceConfig(ServiceConfig<T> serviceConfig) {
        this.serviceConfig = serviceConfig;
    }

    // 注册中心配置
    private ServiceConfig<T> serviceConfig;

    public ReferenceConfig() {
    }

    public ReferenceConfig(Class<T> interfaceProvider) {
        this.interfaceProvider = interfaceProvider;
    }

    public void setInterfaceProvider(Class<T> interfaceProvider) {
        this.interfaceProvider = interfaceProvider;
    }

    /**
     * 获取代理对象
     * @return T：
     */
    public T get() {
        //TODO:使用动态代理完成一定工作
        // 此处一定是使用动态代理完成了一些工作
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class<T>[] classes = new Class[]{interfaceProvider};
//        InvocationHandler handler = new RpcConsumerInvocationHandler(registry,interfaceProvider,group);

        // 使用动态代理生成代理对象
        //TODO:我们每次都会生成一个代理对象，但是这个代理对象是同一个，所以不需要每次都去注册中心寻找服务，只需要找到一个服务即可
        //TODO:我们如何选择代理对象 ？handler watcher ？
        Object helloProxy = Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //1.发现服务，从注册中心，寻找下一个可用的服务
                //2.传入服务的名字，返回ip和端口
                List<InetSocketAddress> address = registry.lookup(interfaceProvider.getName());
                if (log.isDebugEnabled()) {
                    log.debug("服务调用方：发现服务：【{}】的主机号为【{}】",
                            interfaceProvider.getName(), address);
                }
                //2.使用netty连接服务器，发送调用的服务的名字+方法名字+参数列表，得到结果
                //定义线程池，EventLoopGroup
                //整个连接过程放下面并不合理，建立缓存
                //尝试从缓存中获取通道
                Channel channel = rpcBootstrap.CHANNEL_CACHE.get(address);
                if (channel == null) {
                    //await方法会阻塞，会等待连接成功在返回，netty提供异步处理的逻辑
                    channel = NettyBootstrapInitializer.getBootstrap()
                                    .connect((SocketAddress) address).await().channel();
                    //存储缓存
                    rpcBootstrap.CHANNEL_CACHE.put((InetSocketAddress) address, channel);
                }
                if (channel == null) {
                    throw new NetworkException("获取通道发生异常");
                }
                /*
                            同步策略
                 */
//                ChannelFuture channelFuture = channel.writeAndFlush(new RpcRequest(interfaceProvider.getName(), method.getName(), args));
//                if (channelFuture.isDone()) {
//                    Object result = channelFuture.getNow();
//                } else if (!channelFuture.isSuccess()) {
//                    Throwable cause = channelFuture.cause();
//                    throw new NetworkException(cause);
//                }
                /*
                            异步策略
                 */
                return null;
            }

        });

        return (T) helloProxy;
    }
}
